package com.jing.yao.component.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.jing.yao.annotation.UnionUnique;
import com.jing.yao.annotation.Unique;
import com.jing.yao.component.constants.BaseOperationEnum;
import com.jing.yao.component.constants.BmsConstants;
import com.jing.yao.component.dto.Query;
import com.jing.yao.component.dto.QueryEnum;
import com.jing.yao.component.entity.YaoBaseEntity;
import com.jing.yao.component.mapper.YaoBaseMapper;
import com.jing.yao.component.params.page.PageParam;
import com.jing.yao.exception.BusinessException;
import com.jing.yao.exception.BusinessExceptionBuilder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static com.jing.yao.component.constants.ResponseCode.ENTITY_NOT_FOUND;

/**
 * 基础service
 * @author lirui
 * @since 2020-06-13
 */
public interface YaoBaseService<P extends PageParam,T extends YaoBaseEntity> {
    /**
     * 获取直接操作数据库接口
     * @return
     */
    YaoBaseMapper<T> getMapper();

    /**
     * 根据id查询记录
     * @param id
     * @return
     */
    default T selectOneById(Long id) {
        return getMapper().selectById(id);
    }

    /**
     * 排序
     * @param pageParam
     * @return
     */
    default IPage<T> page(P pageParam) {
        Page<T> page = new Page<>();
        page.setCurrent(pageParam.getPageNumber());
        page.setSize(pageParam.getPageSize());

        //设置排序
        if(StringUtils.equals(BmsConstants.ASC,pageParam.getOrder()) && StringUtils.isNotBlank(pageParam.getOrder())){
            page.addOrder(OrderItem.asc(pageParam.getSort()));
        } else if(StringUtils.equals(BmsConstants.DESC,pageParam.getOrder()) && StringUtils.isNotBlank(pageParam.getOrder())){
            page.addOrder(OrderItem.desc(pageParam.getSort()));
        } else {
            page.addOrder(OrderItem.desc("update_time"));
        }
        TimeZone.setDefault(TimeZone.getTimeZone("GMT+8:00"));
        return getMapper().selectPage(page, getWrapper(pageParam));
    }

    /**
     * 抽象查询条件
     * @param param 查询条件
     * @return
     */
    default Wrapper<T> getWrapper(P param) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        //条件的值
        Field[] fields = param.getClass().getDeclaredFields();

        Arrays.stream(fields).forEach(field -> {
            try {
                boolean flag = false;
                field.setAccessible(true);
                if(field.get(param) instanceof String) {
                    flag = StringUtils.isNoneBlank((String)field.get(param));
                } else {
                    flag = field.get(param) != null;
                }
                //判断是否是模糊查询
                if(field.isAnnotationPresent(Query.class) && field.getAnnotation(Query.class).value() == QueryEnum.LIKE) {
                    queryWrapper.like(flag, com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), field.get(param));
                } else {
                    queryWrapper.eq(flag, com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), field.get(param));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });

        return queryWrapper;
    }

    /**
     * 操作前处理
     * @param entity 前端传递的对象
     * @param operationEnum 操作类型
     * @throws BusinessException 阻止程序继续执行或回滚事务
     */
    default void processBeforeOperation(T entity, BaseOperationEnum operationEnum) throws BusinessException{
    }

    /**
     * 操作后续处理
     * @param entity
     * @param operationEnum 操作类型
     * @throws BusinessException  阻止程序继续执行或回滚事务
     */
    default void processAfterOperation(T entity, BaseOperationEnum operationEnum) throws BusinessException {
    }

    /**
     * 插入数据
     * @param entity
     * @throws BusinessException 业务异常
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean insert(T entity) throws BusinessException {
        //保存前处理
        processBeforeOperation(entity, BaseOperationEnum.INSERT);
        checkUniqueField(entity);
        Integer result = getMapper().insert(entity);
        processAfterOperation(entity, BaseOperationEnum.INSERT);
        return result != null && result >= 1;
    }

    /**
     * 校验唯一
     * @param entity
     */
    default void checkUniqueField(T entity) {
        //获取所有属性
        Field[] fields = entity.getClass().getDeclaredFields();

        //判断单一索引
        for (Field field : fields) {
            if (field.isAnnotationPresent(Unique.class)) {
                Unique unique = field.getDeclaredAnnotation(Unique.class);
                QueryWrapper<T> wrapper = Wrappers.query();
                Integer integer = 0;
                try {
                    Object value = getFieldValue(entity, field);
                    if (entity.getId() != null) {
                        wrapper.ne("id", entity.getId());
                    }
                    wrapper.eq(unique.column(), value);
                    integer = getMapper().selectCount(wrapper);
                } catch (Exception e) {
                    continue;
                }
                if (integer >  0) {
                    throw BusinessExceptionBuilder.build(unique.code());
                }
            }
        }

        //判断联合索引
        QueryWrapper<T> unionWrapper = Wrappers.query();
        if (entity.getId() != null) {
            unionWrapper.ne("id", entity.getId());
        }
        Integer integer = 0;
        boolean flag = false;
        for (Field field : fields) {
            if (field.isAnnotationPresent(UnionUnique.class)) {
                UnionUnique unionUnique = field.getDeclaredAnnotation(UnionUnique.class);
                try {
                    Object value = getFieldValue(entity, field);
                    unionWrapper.eq(unionUnique.column(), value);
                    flag = true;
                } catch (Exception e) {
                    continue;
                }
            }
        }

        if (flag) {
            integer = getMapper().selectCount(unionWrapper);
            if (integer >  0) {
                throw BusinessExceptionBuilder.build(entity.getClass().getAnnotation(UnionUnique.class).code());
            }
        }
    }

    /**
     * 获取属性值
     * @param entity
     * @param field
     * @return
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    default Object getFieldValue(T entity, Field field) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), entity.getClass());
        Method readMethod = propertyDescriptor.getReadMethod();
        return readMethod.invoke(entity);
    }

    /**
     * 编辑数据
     * @param entity
     * @throws BusinessException 业务异常
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean update(T entity) throws BusinessException {
        //编辑前处理
        processBeforeOperation(entity, BaseOperationEnum.UPDATE);
        Integer result = getMapper().updateById(entity);
        processAfterOperation(entity, BaseOperationEnum.UPDATE);
        return result != null && result >= 1;
    }

    /**
     * 根据指定字段查询对应的值
     * @param column
     * @param value
     * @return
     */
    default List<T> list(String column, String value) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(column, value);
        return getMapper().selectList(queryWrapper);
    }


    /**
     * 根据指定条件查询对应的记录
     * @param wrapper
     * @return
     */
    default List<T> list(Wrapper<T> wrapper) {
        return getMapper().selectList(wrapper);
    }

    /**ResponseBean
     * 根据ID查询记录
     * @param id
     * @return
     */
    default T getById(Serializable id) {
        return getMapper().selectById(id);
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean removeById(Serializable id) {
        T t = getById(id);
        if(t == null) {
            throw BusinessExceptionBuilder.build(ENTITY_NOT_FOUND);
        }
        processBeforeOperation(t,BaseOperationEnum.DELETE);
        boolean result = SqlHelper.retBool(getMapper().deleteById(id));
        processAfterOperation(t,BaseOperationEnum.DELETE);
        return result;
    }

    /**
     * 删除
     * @param lambdaQueryWrapper
     */
    @Transactional(rollbackFor = Exception.class)
    default void delete(LambdaQueryWrapper<T> lambdaQueryWrapper) {
        getMapper().delete(lambdaQueryWrapper);
    }

    /**
     * 批量删除
     * @param idList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean removeByIds(Collection<? extends Serializable> idList) {
        return SqlHelper.retBool(getMapper().deleteBatchIds(idList));
    }

    /**
     * 查询所有
     * @return
     */
    default List<T> findAll() {
        return getMapper().selectList(Wrappers.emptyWrapper());
    }

    /**
     * @Description 导出
     * @author wangxiaoliang
     * @date 2020-07-15 14:11
     */
    default List<T> exportList(P param, HttpServletResponse response) {
        Wrapper<T> wrapper = getWrapper(param);
        List<T> managementList = getMapper().selectList(wrapper);
       return managementList;
    }

    /**
    * 查询启用数据
    * */
    default List<T> listNotEnabled(String column, String value) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(column, value).eq("enabled",1L);
        return getMapper().selectList(queryWrapper);
    }

    /**
     * 根据指定字段更新值
     * @param id
     * @param column
     * @param value
     */
    default void updateColumn(Long id, String column, Object value) {
        Map<String,Object> params = new HashMap<>();
        params.put(column, value);
        getMapper().updateFieldsById(params, id);
    }

}
